//
// Created by v on 24-12-7.
//

#include "SnakyMediaRun.h"
#include "rt_print.h"
#include "cm_utils.h"
#include "CMUIShowWithLVGL.h"
#ifdef RK3588
#include "CMAIServiceImplRk3588.h"
#endif

#include "cm_logprint.h"
#include "config/CMConfigCpp.h"
#include "CMRecordService.h"

#define MODEL_PATH "/home/cat/j/res/model/best-yolo11.rknn"
#define LABEL_FILE "/home/cat/j/res/model/webfuture.txt"

class AppConfig: public CMConfigCpp
{
public:
    AppConfig(const char *name): CMConfigCpp(name) {}
    ~AppConfig() {}
    std::string model_path()
    {
        return getString("model_file");
    }
    std::string label_file()
    {
        return getString("label_file");
    }
    bool enable_store()
    {
        return getBool("enable_store");
    }
};

SnakyMediaRun::SnakyMediaRun()
{
    init("./app_config.json");
}

SnakyMediaRun::SnakyMediaRun(const char *app_config)
{
    if (app_config)
    {
        init(app_config);
    } else
    {
        init("./app_config.json");
    }
}

int SnakyMediaRun::init(const char *app_config)
{
    impl = NULL;
    buf.length = 0;
    buf.start = NULL;
    exited = false;
    showIt = new CMUIShowWithLVGL();
#ifdef RK3588
    aiService = new CMAIServiceImplRk3588();
#else
    aiService = NULL;
#endif
    appConfig = new AppConfig(app_config);
    if (appConfig->enable_store())
    {
        pri_recordService = new CMRecordService();
    } else
    {
        rtdebug("user disable storage\n");
    }
    return 0;
}

SnakyMediaRun::~SnakyMediaRun()
{
    if (showIt)
    {
        delete showIt;
    }
    if (aiService)
    {
        delete aiService;
    }
    if (appConfig)
    {
        delete appConfig;
    }
}

int SnakyMediaRun::start()
{
    if (!impl)
    {
        impl = (CMVideoImpl *)cm_video_impl_find("v4l2-normal");
    }
    if (!impl)
    {
        rterror("impl not find");
        return -1;
    }
    if (aiService)
    {
        aiService->init();
        int ret = aiService->init_model(appConfig->model_path().c_str(),
            (char*)appConfig->label_file().c_str());
        if (ret < 0)
        {
            rterror("init model failed [%d]", ret);
        }
    }
    const char *dev = "/dev/video0";
    int ret = impl->open(&ctx, dev);
    if (ret < 0)
    {
        rterror("open dev [%s] failed [%d]", dev, ret);
        return -2;
    }
    int index = 0;
    impl->ctrl(&ctx, CM_VIDEO_CMD_SET_CHANNEL, &index);
    int width = 1088;
    impl->ctrl(&ctx, CM_VIDEO_CMD_SET_WIDTH, &width);
    int height = 1920;
    impl->ctrl(&ctx, CM_VIDEO_CMD_SET_HEIGHT, &height);
    int fps = 25;
    impl->ctrl(&ctx, CM_VIDEO_CMD_SET_FPS, &fps);
    int v = CM_VIDEO_FORMAT_JPEG;
    ret = impl->ctrl(&ctx, CM_VIDEO_CMD_SET_PIX_FORMAT, &v);
    if (ret < 0)
    {
        rterror("format set failed [%d]", ret);
        return -2;
    }
    ret = impl->start(&ctx);
    if (ret < 0)
    {
        rterror("start fail [%d] [%s]", ret, dev);
        impl->close(&ctx);
        return -3;
    }
    rtdebug("start done");
    if (pri_recordService)
    {
        pri_recordService->init();
        pri_recordService->start();
    }
    showIt->init();
    showIt->start();
    showIt->showMain();
    return 0;
}

int SnakyMediaRun::stop()
{
    if (!impl)
    {
        return -2;
    }
    rtdebug("stop start");
    if (pri_recordService)
    {
        pri_recordService->stop();
        pri_recordService->deinit();
    }
    impl->stop(&ctx);
    impl->close(&ctx);
    if (aiService)
    {
        aiService->deinit_model();
        aiService->deinit();
    }
    return 0;
}

int SnakyMediaRun::runUntil()
{
    int ret = start();
    if (ret < 0)
    {
        stop();
        return -1;
    }
    unsigned long long r_end;
    unsigned long long frame_count = 0;
    rtdebug("run start");
    while(!exited)
    {
        buf.length = 0;
        unsigned long long r_start = cm_gettime_milli();
        ret = impl->read(&ctx, &buf);
        frame_count++;
        r_end = cm_gettime_milli();
        if (ret < 0)
        {
            rterror("read failed ret = [%d]", ret);
            usleep(500 * 1000);
            continue;
        }
        if (frame_count % 300 == 0)
        {
            rtdebug("frame count [%d], cal each second with last print", frame_count);
        }
        // do other things
        if (aiService)
        {
            std::vector<CMAIRecogItem> results;
            aiService->recognize((const char*)buf.start, buf.length, results);
            std::string text_print;
            text_print = "hello: ";
            for (auto &item : results)
            {
                if (item.score <= 0.5)
                    continue;
                char score_str[10];
                snprintf(score_str, 10, "%.2f", item.score);
                text_print += item.name + " " + score_str + " ";
            }
            showIt->uiShowText(text_print.c_str());
        }
        if (pri_recordService)
        {
            pri_recordService->pushData((unsigned char*)buf.start, buf.length);
        }

        showIt->uiShowImage((const char*)buf.start, buf.length);
        showIt->runOnce();
//        usleep(20000);
    }
    rtdebug("run stop");
    stop();
    return 0;
}

int SnakyMediaRun::runStop()
{
    exited = true;
    return 0;
}
